#include "skynet.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <time.h>
#include <sys/stat.h>

#define NONE					"\033[m "						//无
#define RED                     "\033[0;32;31m "				//红色(建议error)
#define LIGHT_RED          		"\033[1;31m "					//亮红(类似橙色，建议warning)
#define GREEN                   "\033[0;32;32m "				//暗绿(效果一般)
#define LIGHT_GREEN    			"\033[1;32m "					//亮绿(输出效果比较好，建议输出注意栏目)
#define BLUE                    "\033[0;32;34m "				//暗蓝色，效果不好不坏
#define LIGHT_BLUE         		"\033[1;34m "					//亮蓝色，同上效果
#define DARY_GRAY         		"\033[1;30m "					//灰色,效果normal
#define CYAN                    "\033[0;36m "					//褐色？normal
#define LIGHT_CYAN         		"\033[1;36m "					//浅蓝，输出常规日志不错
#define PURPLE                  "\033[0;35m "					//按粉红，normal
#define LIGHT_PURPLE   			"\033[1;35m "					//亮粉红,效果不错
#define BROWN                   "\033[0;33m "					//暗黄,normal
#define YELLOW                  "\033[1;33m "					//亮黄,效果不错
#define LIGHT_GRAY        		"\033[0;37m "					//同none效果
#define WHITE                   "\033[1;37m "					//同none效果

struct logger {
	FILE * handle;
	char * filename;
	int close;
};

static int nextcheck = 0;
static char filetag[32];

char* 
logger_getpath(char* path){
	static char return_path_str[512];
	time_t t = time(0);
	strftime(filetag, sizeof(filetag), "%Y%m%d", localtime(&t));
	return_path_str[0] = 0;
	sprintf(return_path_str, "%s_%s", path, filetag);
	return &(return_path_str[0]);
}

struct logger *
logger_create(void) {
	struct logger * inst = skynet_malloc(sizeof(*inst));
	inst->handle = NULL;
	inst->close = 0;
	inst->filename = NULL;
	return inst;
}

void
logger_release(struct logger * inst) {
	if (inst->close) {
		fclose(inst->handle);
	}
	skynet_free(inst->filename);
	skynet_free(inst);
}

void
logger_checkFileFull(struct logger * inst) {
	struct stat statbuf;  
	//int size = 0;
	int ret = 0;
	if (++nextcheck < 200)
		return;
	nextcheck = 0;

	ret = stat(logger_getpath(inst->filename),&statbuf);
    
	if (ret < 0){
		fclose(inst->handle);
		inst->handle = fopen(logger_getpath(inst->filename),"w");
		return;
	}
}

int 
logger_out_module(void *ud, uint32_t source, void * msg) {
	struct logger * inst = ud;
	time_t timep; struct tm *p;  time(&timep); p=localtime(&timep);
	
	char color[50];
	char *str = msg; 
	int len = 1;
	while (*str!=';' && *str!='\0')  {
		++len;
		++str;
	}

	//是否读到文件末尾
	if (*str != '\0') { 
		strncpy(color, msg, len-1);
		len = len + 1;
		msg = msg + len;
		//取行号
		char lineInfo[100];
		char *str2 = msg; 
		int len2 = 1;
		while (*str2!=';' && *str2!='\0')  {
			++len2;
			++str2;
		}
		strncpy(lineInfo, msg, len2);
		lineInfo[len2 - 1] = '\0';
		len2 = len2 + 1;
		len = len  + len2;

		//info
		if (strncmp(color, "LIGHT_GREEN", 2)==0) {
			//fprintf(inst->handle, NONE"[%02d-%02d %02d:%02d:%02d <%08x>] " LIGHT_GREEN, 
				//(1+p->tm_mon),(p->tm_mday),(p->tm_hour),(p->tm_min),(p->tm_sec), source);
			fprintf(inst->handle, "[%02d-%02d %02d:%02d:%02d] ", 
				(1+p->tm_mon),(p->tm_mday),(p->tm_hour),(p->tm_min),(p->tm_sec));

			fprintf(inst->handle, BROWN"< %s> "CYAN, lineInfo);
		} 
		//debug
		else if (strncmp(color, "YELLOW", 2)==0) {
			fprintf(inst->handle, "[%02d-%02d %02d:%02d:%02d] ", 
				(1+p->tm_mon),(p->tm_mday),(p->tm_hour),(p->tm_min),(p->tm_sec));

			fprintf(inst->handle, BROWN"< %s> "YELLOW, lineInfo);
		} 
		//warning
		else if (strncmp(color, "PURPLE", 2)==0) {
			fprintf(inst->handle, "[%02d-%02d %02d:%02d:%02d] ", 
				(1+p->tm_mon),(p->tm_mday),(p->tm_hour),(p->tm_min),(p->tm_sec));

			fprintf(inst->handle, BROWN"< %s> "PURPLE, lineInfo);
		} 
		//error
		else if (strncmp(color, "RED", 2)==0) {
			fprintf(inst->handle, "[%02d-%02d %02d:%02d:%02d] ", 
				(1+p->tm_mon),(p->tm_mday),(p->tm_hour),(p->tm_min),(p->tm_sec));

			fprintf(inst->handle, BROWN"< %s> "RED, lineInfo);
		} 
		else {
			fprintf(inst->handle, "[%02d-%02d %02d:%02d:%02d] ", 
				(1+p->tm_mon),(p->tm_mday),(p->tm_hour),(p->tm_min),(p->tm_sec));

			fprintf(inst->handle, BROWN"< %s> "BLUE, lineInfo);
		}
	}
	else {
		len = 0;
		fprintf(inst->handle, "[%02d-%02d %02d:%02d:%02d <%08x>] "BLUE, 
			(1+p->tm_mon),(p->tm_mday),(p->tm_hour),(p->tm_min),(p->tm_sec), source);
	}

	return len;
}

static int
logger_cb(struct skynet_context * context, void *ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
	struct logger * inst = ud;
	switch (type) {
	case PTYPE_SYSTEM:
		if (inst->filename) {
			char path[512]; path[0] = '\0';
			sprintf(path,"%s_%s",inst->filename,filetag);
			inst->handle = freopen(path, "a", inst->handle);
		}
		break;
	case PTYPE_TEXT:
		{
			int len = 0;
			len = logger_out_module(ud, source, msg);
			msg = msg + len;
			sz = sz - len;

			fwrite(msg, sz , 1, inst->handle);
			fprintf(inst->handle, NONE"\n");
			fflush(inst->handle);
			logger_checkFileFull(inst);
		}
		break;
	}

	return 0;
}

int
logger_init(struct logger * inst, struct skynet_context *ctx, const char * parm) {
	if (parm) {
		const char* logname = logger_getpath((char*)parm);
		inst->handle = fopen(logname,"a+");
		if (inst->handle == NULL) {
			return 1;
		}

		inst->filename = skynet_malloc(strlen(parm)+10);
		strcpy(inst->filename, parm);
		inst->close = 1;
	} else {
		inst->handle = stdout;
	}
	if (inst->handle) {
		skynet_callback(ctx, inst, logger_cb);
		return 0;
	}
	return 1;
}
